package org.chartsy.rsi;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Stroke;
import java.text.DecimalFormat;
import java.util.LinkedHashMap;
import org.chartsy.main.ChartFrame;
import org.chartsy.main.chart.Indicator;
import org.chartsy.main.data.DataItem;
import org.chartsy.main.data.Dataset;
import org.chartsy.main.utils.DefaultPainter;
import org.chartsy.main.utils.Range;
import org.chartsy.main.utils.SerialVersion;
import org.chartsy.main.utils.StrokeGenerator;
import org.openide.nodes.AbstractNode;
/**
*
* @author viorel.gheba
*/
public class RSI
extends Indicator
{
private static final long serialVersionUID = SerialVersion.APPVERSION;
public static final String RSI = "rsi";
private IndicatorProperties properties;
public RSI()
{
super();
properties = new IndicatorProperties();
}
public String getName()
{
return "RSI";
}
public String getLabel()
{
return properties.getLabel() + " (" + properties.getPeriod() + ")";
}
public String getPaintedLabel(ChartFrame cf)
{
return getLabel();
}
public Indicator newInstance()
{
return new RSI();
}
public LinkedHashMap getHTML(ChartFrame cf, int i)
{
LinkedHashMap ht = new LinkedHashMap();
DecimalFormat df = new DecimalFormat("#,##0.00");
double[] values = getValues(cf, i);
String[] labels =
{
"RSI:"
};
ht.put(getLabel(), " ");
if (values.length > 0)
{
Color[] colors = getColors();
for (int j = 0; j < values.length; j++)
{
ht.put(getFontHTML(colors[j], labels[j]),
getFontHTML(colors[j], df.format(values[j])));
}
}
return ht;
}
@Override
public Range getRange(ChartFrame cf)
{
return new Range(0, 100);
}
public void paint(Graphics2D g, ChartFrame cf, Rectangle bounds)
{
Dataset d = visibleDataset(cf, RSI);
if (d != null)
{
if (maximized)
{
Range range = getRange(cf);
DefaultPainter.line(g, cf, range, bounds, d, properties.getColor(), properties.getStroke()); // paint line
if (properties.getInsideVisibility())
{
paintFill(g, cf, d, bounds, range, properties.getInsideTransparentColor(), 30d, 0d, false); // paint fill
paintFill(g, cf, d, bounds, range, properties.getInsideTransparentColor(), 70d, 100d, true); // paint fill
}
}
}
}
public void calculate()
{
Dataset initial = getDataset();
if (initial != null && !initial.isEmpty())
{
int period = properties.getPeriod();
Dataset d = getDataset(initial, period);
addDataset(RSI, d);
}
}
public boolean hasZeroLine()
{
return false;
}
public boolean getZeroLineVisibility()
{
return false;
}
public Color getZeroLineColor()
{
return null;
}
public Stroke getZeroLineStroke()
{
return null;
}
public boolean hasDelimiters()
{
return true;
}
public boolean getDelimitersVisibility()
{
return true;
}
public double[] getDelimitersValues()
{
return new double[]
{
30d, 50d, 70d
};
}
public Color getDelimitersColor()
{
return new Color(0xbbbbbb);
}
public Stroke getDelimitersStroke()
{
return StrokeGenerator.getStroke(1);
}
public Color[] getColors()
{
return new Color[]
{
properties.getColor()
};
}
public double[] getValues(ChartFrame cf)
{
Dataset d = visibleDataset(cf, RSI);
if (d != null)
{
return new double[]
{
d.getLastClose()
};
}
return new double[]
{
};
}
public double[] getValues(ChartFrame cf, int i)
{
Dataset d = visibleDataset(cf, RSI);
if (d != null)
{
return new double[]
{
d.getCloseAt(i)
};
}
return new double[]
{
};
}
public boolean getMarkerVisibility()
{
return properties.getMarker();
}
public AbstractNode getNode()
{
return new IndicatorNode(properties);
}
@Override
public Double[] getPriceValues(ChartFrame cf)
{
return new Double[]
{
new Double(10), new Double(30), new Double(50), new Double(70), new Double(90)
};
}
private Dataset getDataset(final Dataset initial, final int period)
{
int count = initial.getItemsCount();
Dataset result = Dataset.EMPTY(count);
Dataset source_dataset = null;
if (properties.getSourceDataset() == IndicatorProperties.SOURCE_CLOSE)
{
source_dataset = initial;
} else
{
source_dataset = Dataset.HMA(initial, properties.getHmaPeriod());
}
// Build upward dataset
Dataset upward = Dataset.EMPTY(count);
Dataset downward = Dataset.EMPTY(count);
upward.setDataItem(0, new DataItem(source_dataset.getTimeAt(0), 0));
downward.setDataItem(0, new DataItem(source_dataset.getTimeAt(0), 0));
for (int i = 1; i < count; i++)
{
if (source_dataset.getCloseAt(i) > source_dataset.getCloseAt(i - 1))
{
upward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), source_dataset.getCloseAt(i) - source_dataset.getCloseAt(i - 1)));
downward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), 0));
} else if (source_dataset.getCloseAt(i) < source_dataset.getCloseAt(i - 1))
{
upward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), 0));
downward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), source_dataset.getCloseAt(i - 1) - source_dataset.getCloseAt(i)));
} else
{
// last close and previous close are equal, u and d are 0
upward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), 0));
downward.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), 0));
}
}
Dataset rsup = Dataset.EMAWilder(upward, period);
Dataset rsdown = Dataset.EMAWilder(downward, period);
for (int i = 0; i < count; i++)
{
if (rsdown.getCloseAt(i) == 0)
{
result.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), 100));
} else
{
double rs = rsup.getCloseAt(i) / rsdown.getCloseAt(i);
double rsival = 100d - (100d / (1d + rs));
result.setDataItem(i, new DataItem(source_dataset.getTimeAt(i), rsival));
}
}
return result;
}
}